package com.qiji.video.web.controller;
import com.github.pagehelper.PageInfo;
import com.qiji.video.bean.Videos;
import com.qiji.video.bean.extend.FuzzyQuery_Video;
import com.qiji.video.service.IVideoService;
import com.qiji.video.service.impl.RestTemplateToInterface;
import com.qiji.video.util.FileUtil;
import com.qiji.video.util.Result;
import com.qiji.video.util.ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

import org.apache.catalina.util.RequestUtil;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 视频管理模块
 */

@Api(
        tags = {"视频模块"}
)
@RestController
@RequestMapping({"/auth/admin/videos"})
public class VideoController {
    @Autowired
    private IVideoService videoService;

    @Autowired
    private RestTemplateToInterface restTemplateToInterface;

    @Resource
    HttpServletRequest request;
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd/");
    //处理文件上传
//    @PostMapping("/upload")
//    public Map<String, Object> fileupload(MultipartFile file, HttpServletRequest req){
//        Map<String, Object> result = new HashMap<>();
//        String originName = file.getOriginalFilename();
//        if(!originName.endsWith(".jpg")){
//            result.put("status","error");
//            result.put("msg","文件类型不对");
//            return result;
//        }
//        String format = sdf.format(new Date());
//        String realPath = req.getServletContext().getRealPath("/")+format;
//        File folder = new File(realPath);
//        if (!folder.exists()){
//            folder.mkdirs();
//        }
//        String newName = UUID.randomUUID().toString() + ".jpg";
//        try {
//            file.transferTo(new File(folder, newName));
//            String url = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/" + format + newName;
//            result.put("status","error");
//            result.put("url",url);
//        } catch (IOException e) {
//            result.put("status","error");
//            result.put("msg",e.getMessage());
//        }
//        return result;
//    }
    @Value("${yuan.file.root.path}")
    public String fileRootPath;

    @ApiOperation("使用网上接口")
    @GetMapping("/useApi")
    public Result useApi(){

        Map<String,String> params=new HashMap<>();
        params.put("api_key","91530e10ad410e11");
        return ResultUtil.success(restTemplateToInterface.doGetWith2("https://api.muxiaoguo.cn/api/163reping",params));
    }


    @ApiOperation("模糊查询视频")
    @GetMapping("/fuzzyEnquiryVideos")
    public Result fuzzyEnquiryVideos(Integer pageNum, Integer pageSize, FuzzyQuery_Video fuzzyQuery_video){ //前端把模糊信息放在一个video对象
        PageInfo<Videos> pageInfo = videoService.pageQueryfuzzyEnquiryVideos(pageNum, pageSize, fuzzyQuery_video);
        //有个结构，待完成  已完成，单分区这种模式 网上都是单选分区
        //要是模糊查询选择多个分区
        //可以先按一个分区 名称模糊 分类 查出结果x
        //再判断已被选出的电影里是否含有第二个分区
        return ResultUtil.success(pageInfo);
    }
    @ApiOperation("查询视频类型")
    @GetMapping("/enquiryVideosType")
    public Result enquiryVideosType(Integer id){
        List<String> videoType=videoService.selectVideoType(id);
        return ResultUtil.success(videoType);
    }

    @ApiOperation("更新视频类型")
    @PostMapping("/updateTypeVideo")
    public Result updateTypeVideo(Integer vid,@RequestParam List<String> VType){
        videoService.deleteVideoType(vid);
//        System.out.println(vid);
//        System.out.println(VType);
        videoService.insertVideoType(vid,VType);
        return ResultUtil.success();
    }

    @ApiOperation("添加视频 含类型")
    @PostMapping("/addVideosWithType")
    public Result addVideosWithType(Videos videos,@RequestParam List<String> VType){
        videoService.addVideos(videos);
        int vid=videoService.getLastID();
        System.out.println(vid);
        videoService.deleteVideoType(vid);
//        System.out.println(vid);
//        System.out.println(VType);
        videoService.insertVideoType(vid,VType);
        return ResultUtil.success();
    }


    @ApiOperation("根据视频id查询所有视频信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id",value = "查询视频的ID值",dataType = "int"),
    })
    @GetMapping("/selectVideosDetailById")
    public Result selectVideosDetailById(int id){
        return ResultUtil.success(videoService.selectVideosDetail(id));
    }

    @ApiOperation("通过id删除视频")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id",value = "要删除视频的ID值",dataType = "int"),
    })
    @DeleteMapping("/deleteVideosById")
    public Result deleteTypeById(Integer id){
//        Videos videos=videoService.selectVideosDetail(id);
//        //获取原文件名
//        String name=videos.getFileName();
//        //获取文件后缀
//        String subffix=name.substring(name.lastIndexOf(".")+1,name.length());
//        File file;
//        if(!subffix.equals("tif")&&!subffix.equals("jpg")&&!subffix.equals("jpeg")&&!subffix.equals("ico")&&!subffix.equals("tiff")&&!subffix.equals("gif")&&!subffix.equals("webp")&&!subffix.equals("png")&&!subffix.equals("bmp")){
//            file=new File(ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/pictures/"+videos.getFileName());
//        }else{
//            file=new File(ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/videos/"+videos.getFileName());
//        }
//        file.delete();
        videoService.deleteVides(id);
        return ResultUtil.success();
    }


    @ApiOperation("修改视频信息")
    @PostMapping("/updateVideos")
    public Result updateVideoType(Videos videos){
        int id=videos.getId();
        Videos origin=videoService.selectVideosDetail(id);
        if(videos.getFileName()!=null)origin.setFileName(videos.getFileName());
        if(videos.getName()!=null)origin.setName(videos.getName());
        if(videos.getScore()!=null)origin.setScore(videos.getScore());
        if(videos.getBackImg()!=null)origin.setBackImg(videos.getBackImg());
        if(videos.getClicks()!=null)origin.setClicks(videos.getClicks());
        if(videos.getCoverImg()!=null)origin.setCoverImg(videos.getCoverImg());
        if(videos.getDirector()!=null)origin.setDirector(videos.getDirector());
//        if(videos.getId()!=null)origin.setId(videos.getId());
        if(videos.getLikes()!=null)origin.setLikes(videos.getLikes());
        if(videos.getPartitionId()!=null)origin.setPartitionId(videos.getPartitionId());
        if(videos.getPublicTime()!=null)origin.setPublicTime(videos.getPublicTime());
        if(videos.getRegion()!=null)origin.setRegion(videos.getRegion());
        if(videos.getShowTime()!=null)origin.setShowTime(videos.getShowTime());
        if(videos.getSortNum()!=null)origin.setSortNum(videos.getSortNum());
        if(videos.getStarring()!=null)origin.setStarring(videos.getStarring());
        if(videos.getState()!=null)origin.setState(videos.getState());
        if(videos.getSynopsis()!=null)origin.setSynopsis(videos.getSynopsis());
        if(videos.getTrampleds()!=null)origin.setTrampleds(videos.getTrampleds());
        videoService.updateVideos(origin);
        return ResultUtil.success();
    }

    @ApiOperation("修改视频状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "videoId",value = "要修改视频的ID值",dataType = "int"),
            @ApiImplicitParam(name = "status",value = "状态",dataType = "String"),
    })
    @PostMapping("/updateVideosStatus")
    public Result updateVideoType(Integer videoId,String status){
        Videos videos=videoService.selectVideosDetail(videoId);
        videos.setState(status);
        //状态是个string值？
        return ResultUtil.success(videos);
    }

    @ApiOperation("修改推荐指数")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "videoId",value = "要修改视频的ID值",dataType = "int"),
            @ApiImplicitParam(name = "sortNum",value = "推荐指数",dataType = "int"),
    })
    @PostMapping("/updateVideosSortNum")
    public Result updateVideoType(Integer videoId,Integer sortNum){
        Videos videos=videoService.selectVideosDetail(videoId);
        videos.setSortNum(sortNum);
        return ResultUtil.success(videos);
    }
    @ApiOperation("文件上传")
    @PostMapping("/upload")
    public Result upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        String filePath = ""; // 文件保存的位置
        String urlPath = "";// 文件web浏览路径
        Assert.isTrue(!file.isEmpty(), "文件为空");
        // 原始名 以 a.jpg为例
        String originalFilename = file.getOriginalFilename();
        // 获取后缀并拼接'/'用于分类,也可以用日期 例: suffix = "jpg/"
        String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1) + "/";
        // 加上时间戳生成新的文件名,防止重复 newFileName = "1595511980146a.jpg"
        String newFileName = System.currentTimeMillis() + originalFilename;
        filePath = fileRootPath + suffix + newFileName;
        System.out.println(filePath);
        try {
            File file1 = new File(filePath);
            if (!file1.exists()) file1.mkdirs(); // 要是目录不存在,创建一个
            file.transferTo(file1);              // 保存起来
            urlPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/archive/" + suffix + newFileName;


        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultUtil.success(urlPath);
    }

    @ApiOperation("添加视频")
    @PostMapping("/addVideos")
    public Result addVideo(Videos videos){

        videoService.addVideos(videos);
        return ResultUtil.success();
    }

    @ApiOperation("上传视频-已废弃")
    @PostMapping("/uploadVideos")
    public Result uploadVideo(int id, MultipartFile multipartFile){

        //添加视频信息到数据库
//        videoService.addVideos(videos);
//        videoService.uploadVideos(file);
        Videos videos=videoService.selectVideosDetail(id);



        //获取原文件名
        String origin_name=videos.getFileName();
        //获取文件后缀
        String origin_subffix=origin_name.substring(origin_name.lastIndexOf(".")+1,origin_name.length());
        File origin_file;
        if(origin_name!=null){
            if(!origin_subffix.equals("tif")&&!origin_subffix.equals("jpg")&&!origin_subffix.equals("jpeg")&&!origin_subffix.equals("ico")&&!origin_subffix.equals("tiff")&&!origin_subffix.equals("gif")&&!origin_subffix.equals("webp")&&!origin_subffix.equals("png")&&!origin_subffix.equals("bmp")){
                origin_file=new File(ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/videos/"+videos.getFileName());
            }else{
                origin_file=new File(ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/pictures/"+videos.getFileName());
            }
            boolean result = false;
            int tryCount = 0;
            while(!result && tryCount++ <10)
            {
                System.gc();
                result=origin_file.delete();
            }
//            origin_file.delete();
        }


        //视频上传
        //获取原文件名
        String name=multipartFile.getOriginalFilename();
        //获取文件后缀
        String subffix=name.substring(name.lastIndexOf(".")+1,name.length());
        //控制格式
        if(subffix.equals("")||(!subffix.equals("mp4")&&!subffix.equals("mov")&&!subffix.equals("avi")&&!subffix.equals("wmv")&&!subffix.equals("m4v")&&!subffix.equals("dat")&&!subffix.equals("flv")&&!subffix.equals("mkv")
                &&!subffix.equals("tif")&&!subffix.equals("jpg")&&!subffix.equals("jpeg")&&!subffix.equals("ico")&&!subffix.equals("tiff")&&!subffix.equals("gif")&&!subffix.equals("webp")&&!subffix.equals("png")&&!subffix.equals("bmp")))
        {
            System.out.println(subffix);
            return ResultUtil.error("视频格式不对");
        }

        //新的文件名以日期命名
        String fileName=new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        //获取项目路径到webapp
//        String filepath=request.getServletContext().getRealPath("/")+"files\\";
        //获取项目根路径并转到static/videos
        String path;
        if(!subffix.equals("tif")&&!subffix.equals("jpg")&&!subffix.equals("jpeg")&&!subffix.equals("ico")&&!subffix.equals("tiff")&&!subffix.equals("gif")&&!subffix.equals("webp")&&!subffix.equals("png")&&!subffix.equals("bmp")){
            path = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/videos/";
//            path = ResourceUtils.getURL("classpath:").getPath()+"static/videos/";
        }
        else{
            path = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/pictures/";
        }

//        System.out.println("path="+path);
//        System.out.println("filename="+fileName);
        File file=new File(path);
//        System.out.println("file="+file);

        if(!file.exists())//文件夹不存在就创建
        {
            file.mkdirs();
        }
        //保存文件
        try {
            multipartFile.transferTo(new File(file.getAbsolutePath()+"/"+fileName+"."+subffix));
        } catch (IOException e) {
            e.printStackTrace();
        }
//        String realPath=file+"\\"+fileName+"."+subffix;
//        String simulationVideo="/videos/"+fileName+"."+subffix;
        videos.setFileName(fileName+"."+subffix);

        videoService.updateVideos(videos);
        return ResultUtil.success();
    }



/**
 * 获取视频流
 * @param response
 * @param videoId 视频存放信息索引
 * @return
 * @author xWang
 * @Date 2020-05-20
 */
    @ApiOperation("下载视频，?播放")
    @PostMapping("/getVideo/{videoId}")
    public void getVideo(HttpServletRequest request, HttpServletResponse response, @PathVariable Integer videoId)
    {
        //视频资源存储信息
        Videos videoSource=videoService.selectVideosDetail(videoId);
//        VideoSource videoSource = videoSourceService.selectById(videoId);
//        videoSource.setName(videoSource.getName()+".mp4");

        response.reset();
        //获取从那个字节开始读取文件
        String rangeString = request.getHeader("Range");

        try {
            //获取响应的输出流
            OutputStream outputStream = response.getOutputStream();
//            File file = new File(videoSource.getFileAddress());
            String name=videoSource.getFileName();
            String subffix=name.substring(name.lastIndexOf(".")+1,name.length());

            String file_name=name.substring(36+subffix.length(),name.length());

            File file;
            file=new File(fileRootPath+subffix+"/"+file_name);

            System.out.println(file_name);
            System.out.println(fileRootPath+subffix+"/"+file_name);

//            File file;
//            if(!subffix.equals("tif")&&!subffix.equals("jpg")&&!subffix.equals("jpeg")&&!subffix.equals("ico")&&!subffix.equals("tiff")&&!subffix.equals("gif")&&!subffix.equals("webp")&&!subffix.equals("png")&&!subffix.equals("bmp")){
//                file=new File(ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/videos/"+videoSource.getFileName());
//            }else{
//                file=new File(ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/pictures/"+videoSource.getFileName());
//            }
            //可能只能固定位置了
            //项目工程文件+static/videos/

            if(file.exists()){
                RandomAccessFile targetFile = new RandomAccessFile(file, "r");
                long fileLength = targetFile.length();
                //播放
                if(rangeString != null){

                    long range = Long.valueOf(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
                    //设置内容类型
                    response.setHeader("Content-Type", subffix);
                    //设置此次相应返回的数据长度
                    response.setHeader("Content-Length", String.valueOf(fileLength - range));
                    //设置此次相应返回的数据范围
                    response.setHeader("Content-Range", "bytes "+range+"-"+(fileLength-1)+"/"+fileLength);
                    //返回码需要为206，而不是200
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设定文件读取开始位置（以字节为单位）
                    targetFile.seek(range);
                }else {//下载
                    response.reset();
                    response.setContentType("application/"+subffix+";charset=UTF-8");

                    //设置响应头，把文件名字设置好
//                    response.setHeader("Content-Disposition", "attachment; filename="+videoSource.getFileName() );
//                    System.out.println(videoSource.getName());
                    response.setHeader("Content-Disposition", "attachment; filename="+file_name);
                    //设置文件长度
                    response.setHeader("Content-Length", String.valueOf(fileLength));
                    //解决编码问题
                    response.setHeader("Content-Type","application/octet-stream");
                }


                byte[] cache = new byte[1024 * 300];
                int flag;
                while ((flag = targetFile.read(cache))!=-1){
                    outputStream.write(cache, 0, flag);
                }
            }else {
//                String message = "file:"+videoSource.getFileName()+" not exists";
                String message = "file:"+file_name+" not exists";
                //解决编码问题
                response.setHeader("Content-Type","application/json");
                outputStream.write(message.getBytes(StandardCharsets.UTF_8));
            }

            outputStream.flush();
            outputStream.close();

        } catch (FileNotFoundException e) {

        } catch (IOException e) {

        }
    }


    private final static String utf8="utf-8";
    private final static long PER_PAGE=1024l*1024l*50l;
    private final static String DOWN_PATH="C:\\Users\\Mirai\\Downloads";
//    private final static String DOWN_PATH="E:\\Download\\1\\";

    ExecutorService pool= Executors.newFixedThreadPool(10);
    class FileInfo{
        long fSize;
        String fName;

        public FileInfo(long fSize,String fName){
            this.fName=fName;
            this.fSize=fSize;
        }
    }
    private FileInfo download(long start,long end,long page,String fName) throws Exception {
        //断点下载
        File file=new File(DOWN_PATH,page+"-"+fName);
        if(file.exists() && page != -1 && file.length() == PER_PAGE){
            return null;
        }

        HttpClient client= HttpClients.createDefault();
        HttpGet httpGet=new HttpGet("blob:http://localhost:9000/cc3fcaec-eba2-401a-826d-6ee08945004e");
//        HttpGet httpGet=new HttpGet("http://127.0.0.1:9000/download");
        httpGet.setHeader("Range","bytes="+start+"-"+end);

        HttpResponse response=client.execute(httpGet);
        String fSize=response.getFirstHeader("fSize").getValue();
        fName= URLDecoder.decode(response.getFirstHeader("fName").getValue(),utf8) ;

        HttpEntity entity=response.getEntity();
        InputStream is=entity.getContent();

        FileOutputStream fos=new FileOutputStream(file);
        byte[] buffer=new byte[1024];
        int ch;
        while((ch = is.read(buffer)) != -1){
            fos.write(buffer,0,ch);
        }

        if(end -Long.valueOf(fSize) > 0){
            mergeFile(fName,page);
        }

        is.close();
        fos.flush();
        fos.close();
        return new FileInfo(Long.valueOf(fSize),fName);
    }

    private void mergeFile(String fName, long page) throws Exception {
        File file =new File(DOWN_PATH,fName);
        BufferedOutputStream os=new BufferedOutputStream(new FileOutputStream(file));

        for(int i=0;i<=page;i++){
            File temFile=new File(DOWN_PATH,i+"-"+fName);
            while(!file.exists() || (i!=page && file.length()<PER_PAGE)){
                Thread.sleep(100);
            }
            byte[] bytes=FileUtils.readFileToByteArray(temFile);
            os.write(bytes);
            os.flush();
            temFile.delete();

        }
        File file1=new File(DOWN_PATH,-1+"-null");
        file1.delete();
        os.flush();
        os.close();
    }

    @ApiOperation("分片下载视频")
    @PostMapping("/sharedownloadVideo")
    public void sharedownloadVideo(HttpServletRequest request, HttpServletResponse response) throws  Exception{
        FileInfo fileInfo = download(0,10,-1,null);
        if(fileInfo != null){
            long pages=fileInfo.fSize / PER_PAGE;
            for( long i=0;i<pages;i++){
                pool.submit(new DownLoad(i*PER_PAGE , (i+1)*PER_PAGE-1 , i  ,fileInfo.fName));
            }
        }
    }

    class DownLoad implements Runnable{
        long start,page,end;
        String fName;

        public DownLoad(long start, long page, long end, String fName) {
            this.start = start;
            this.page = page;
            this.end = end;
            this.fName = fName;
        }

        @Override
        public void run() {
            try {
                download(start,end,page,fName);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }



    @ApiOperation("下载视频第二种")
    @PostMapping("/breakPointDownload")
    /*@ResponseBody  */                                                      /*, @PathVariable Integer videoId*/
    public void breakPointDownload(HttpServletRequest request, HttpServletResponse response) throws Exception {
        File file=new File("E:\\Download\\1\\1.mp4");
        response.setCharacterEncoding(utf8);
        InputStream is=null;
        OutputStream os=null;
        System.out.println("到这了");
        try {
            //分片下载
            long fSize =file.length();
            response.setContentType("application/x-download");
            String fileName= URLEncoder.encode(file.getName(),utf8);
            response.addHeader("Content-Disposition","attachment;filename="+fileName);
            response.setHeader("Accept-Range","bytes");

            response.setHeader("fSize",String.valueOf(fSize));
            response.setHeader("fName",fileName);

            long pos=0,last=fSize-1,sum=0;
            if(null != request.getHeader("Range")){
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

                String numRange=request.getHeader("Range").replaceAll("bytes=","");
                String[] strRange=numRange.split("-");
                if(strRange.length == 2){
                    pos=Long.parseLong(strRange[0].trim());
                    last=Long.parseLong(strRange[1].trim());
                    if(last > fSize-1){
                        last=fSize-1;
                    }
                }else{
                    pos=Long.parseLong(numRange.replaceAll("-","").trim());
                }
            }
            long rangeLength=last-pos+1;
            String contentRange =new StringBuffer("bytes ").append(pos).append("-").append(last).append("/").append(fSize).toString();
            response.setHeader("Content-Range",contentRange);
            response.setHeader("Content-Length",String.valueOf(rangeLength));

            os=new BufferedOutputStream(response.getOutputStream());
            is=new BufferedInputStream(new FileInputStream(file));
            is.skip(pos);
            byte[] buffer =new byte[1024];
            int length=0;
            while(sum < rangeLength){
                length =is.read(buffer,0,((rangeLength-sum) <= buffer.length?((int) (rangeLength-sum)):buffer.length));
                sum+=length;
                os.write(buffer,0,length);


            }
            System.out.println("下载完成");
        }finally {
            if(is!=null){
                is.close();
            }
            if(os!=null){
                os.close();
            }
        }
    }
}
